<template>
  <div>
    <el-dialog
      v-dialogDrag
      :title="dialogTitle"
      :visible.sync="dialogVisible"
      class="dialogStyleSmall"
      :before-close="cancel"
    >
      <el-form v-if="dialogVisible" ref="form" label-width="auto">
        <el-row style="margin-bottom:185px">
          <el-form-item label="菜单权限：" class="el-tree-wrap">
            <p class="all-expand">
              <span v-if="AddExpand" @click="unFoldAll()"><i class="el-icon-caret-bottom" />全部展开</span>
              <span v-else @click="closeAll()"><i class="el-icon-caret-top" />全部关闭</span>
            </p>
            <div>
              <el-tree
                v-if="openOrNot"
                ref="menu"
                :data="menuOptions"
                show-checkbox
                node-key="menuId"
                empty-text="加载中，请稍后"
                :props="defaultPropsMenu"
                :default-expand-all="defaultExpand"
                :highlight-current="true"
                :render-content="renderContent"
                @check="handleChange"
              />
            </div>
          </el-form-item>
        </el-row>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <DialogFooter />
      </div>
    </el-dialog>
    <!-- 初始化 编辑和添加页面 -->
    <add-or-update v-if="addOrUpdateVisible" ref="addOrUpdate" @menuData="getMenuData" />
  </div>
</template>
<script>
import AddOrUpdate from '@/components/System/Role/RoleDataScope'
import { getMenuIdsByRoleId, getSelectedIdAndDefaultPermissionsByRoleId,
  addOrupdateRoleMenuAndDataScope, getDefaultPermissionsByRoleId } from '@/api/system/role'
  // dialog-footer
import DialogFooter from '@/components/Common/Btns/DialogFooter/index'
export default {
  components: { AddOrUpdate, DialogFooter },
  data() {
    return {
      // 树是否全部展开
      AddExpand: true,
      // 弹出的对话框的标题
      dialogTitle: '',
      // 对话框是否弹出显示
      dialogVisible: false,
      addOrUpdateVisible: false,

      //   树形菜单
      // 默认勾选节点key的值
      checkedKeys: [],
      // 树形菜单数据
      menuOptions: [],
      openOrNot: true,
      defaultExpand: false,
      // 选中的菜单树数据
      treeSelected: [],
      // 加载树形菜单结构
      defaultPropsMenu: {
        children: 'children',
        label: 'menuName'
      },
      // 角色ID
      roleId: '',
      menuIds: [],
      //   用于封装角色分配数据权限传回来的值 start
      menuList: [],
      // 用于封装 整个菜单树 数据权限的数组
      roleIdAndMenuListAll: [],
      // 用于存储菜单默认的数据权限
      defauleDataScopList: []
    }
  },
  // watch: {
  //   'defauleDataScopList': 'selectDefaultPermissionsByRoleId'
  // },
  methods: {
    // 全部展开
    unFoldAll() {
      this.treeSelected = this.$refs.menu.getCheckedKeys().concat(this.$refs.menu.getHalfCheckedKeys())
      this.AddExpand = false
      this.defaultExpand = true
      this.openOrNot = false
      setTimeout(() => {
        this.openOrNot = true
        this.$nextTick(() => {
          this.$refs.menu.setCheckedKeys(this.treeSelected)
        })
      }, 10)
    },
    // 全部关闭
    closeAll() {
      this.treeSelected = this.$refs.menu.getCheckedKeys().concat(this.$refs.menu.getHalfCheckedKeys())
      this.AddExpand = true
      this.defaultExpand = false
      this.openOrNot = false
      setTimeout(() => {
        this.openOrNot = true
        this.$nextTick(() => {
          this.$refs.menu.setCheckedKeys(this.treeSelected)
        })
      }, 10)
    },
    showView(roleId) {
      var _this = this
      _this.dialogTitle = '菜单和数据权限分配'
      _this.dialogVisible = true
      _this.roleId = roleId
      /**
       * 编辑菜单和数据权限加载的方法
       * */
      _this.selectMenuScopeByRoleId(roleId)
    },
    // 菜单树形加载
    getMenuTreeData() {
      var _this = this
      const roleId = _this.roleId
      getMenuIdsByRoleId(roleId).then(resp => {
        if (resp) {
          _this.menuOptions = resp.data
        } else {
          _this.msgError(resp.message)
        }
      })
    },

    // 所有菜单节点数据
    getMenuAllCheckedKeys() {
      // 目前被选中的菜单节点
      const checkedKeys = this.$refs.menu.getHalfCheckedKeys()
      // 半选中的菜单节点
      const halfCheckedKeys = this.$refs.menu.getCheckedKeys()
      checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys)
      return checkedKeys
    },

    // 菜单树节点加载 设置菜单后面是否显示“数据权限”字样
    renderContent(h, { node, data, checked, store }) {
      // 判断菜单类型
      var menuType = data.menuType
      // 判断节点是否选中
      var isNodeCheck = false
      /** 当节点是选中状态时显示数据权限
       * 当节点是半选中状态时也显示数据权限
       */
      if (node.checked) {
        isNodeCheck = true
      } else {
        /** 获取次节点下面的子节点
         * 当子节点其中也有选择状态时设置isNodeCheck = true
         * 并且跳出循环
         */
        var childNodes = node.childNodes
        for (var i = 0; i < childNodes.length; i++) {
          if (childNodes[i].checked) {
            isNodeCheck = true
            break
          }
        }
      }
      /**
       * 当菜单类型为菜单（C）时 并且 次菜单是选中状态或者半选中状态
       * 否则并且不显示 “数据权限字样”
       */
      if (menuType === 'C' && isNodeCheck) {
        return (
          <span class='custom-tree-node'>
            <span>{node.label}</span>
            <span style='margin-left:20px'>
              <el-button
                size='mini'
                type='text'
                on-click={() => this.append(data, event)}
              >
                数据权限
              </el-button>
            </span>
          </span>
        )
      } else {
        return (
          <span class='custom-tree-node'>
            <span>{node.label}</span>
          </span>
        )
      }
    },

    // 点击数据权限是调用的方法
    append(data, event) {
      var _this = this
      _this.addOrUpdateVisible = true
      var objType = 'role'
      _this.$nextTick(() => {
        _this.$refs.addOrUpdate.showAddMenuView(objType, data, event)
      })
    },

    // 获取子集传过来的数据权限对象，并遍历菜单树放到对应节点的数据权限存放的字段（dataScopList）中
    getMenuData(menuData) {
      var _this = this
      const menuId = menuData.menuId
      const newDataScopList = menuData.dataScopList
      // 遍历菜单树，把数据权限存储到节点的dataScopList中
      _this.changeMenuOptions(menuId, newDataScopList)
    },

    // 创建用于存储RoleIdAndMenuList 的对象
    createRoleIdAndMenuList(roleId, menuList) {
      var RoleIdAndMenuList = {
        'objId': roleId,
        'menuList': menuList
      }
      return RoleIdAndMenuList
    },

    // 取消按钮（数据权限）
    cancel() {
      var _this = this
      _this.dialogVisible = false
      // 清空数组
      _this.roleIdAndMenuListAll = []
    },

    // 所有菜单节点数据
    getMenuAllCheckedNodes() {
      // 目前被选中的菜单节点
      const checkedNodes = this.$refs.menu.getHalfCheckedNodes()
      // 半选中的菜单节点
      const halfCheckedNodes = this.$refs.menu.getCheckedNodes()
      checkedNodes.unshift.apply(checkedNodes, halfCheckedNodes)
      return checkedNodes
    },
    // 确认按钮
    submitForm() {
      var _this = this
      // 获取选中的节点
      var checkNode = _this.getMenuAllCheckedNodes()
      // 把选中的节点存到menuList中
      _this.menuList = checkNode
      var createRoleIdAndMenuList = _this.createRoleIdAndMenuList(
        _this.roleId,
        _this.menuList
      )
      _this.roleIdAndMenuListAll.push(createRoleIdAndMenuList)
      var roleIdAndMenuListAll = _this.roleIdAndMenuListAll
      // 封装的数组转化成json串
      var jsonString = JSON.stringify(roleIdAndMenuListAll)
      // 数据传输到后台
      addOrupdateRoleMenuAndDataScope(jsonString).then(resp => {
        if (resp) {
          _this.dialogVisible = false
          // 清空数组
          _this.roleIdAndMenuListAll = []
          _this.msgSuccess('菜单和数据权限分配成功')
        } else {
          _this.msgError(resp.message)
        }
      })
    },

    // 当复选框选中状态改变时
    handleChange(data, nodefunction) {
      var _this = this
      // 定义变量用于判断当前节点有没有选择
      var isMenuId = true
      // 当天节点改变状态的值
      var menuId = data.menuId
      // 获取数组中被选中节点的值
      var checkedKeys = nodefunction.checkedKeys
      // 当前节点是选中状态标识设置为false
      for (var i = 0; i < checkedKeys.length; i++) {
        if (menuId === checkedKeys[i]) {
          isMenuId = false
        }
      }
      // 默认数据权限
      const defauleDataScopList = _this.defauleDataScopList
      // isMenuId 为 true时 表示该节点没有被选中
      if (isMenuId && data.menuType === 'C') {
        // 当前节点没有被选中,遍历树 把该节点的数据权限设为默认数据权限
        _this.changeMenuOptions(menuId, defauleDataScopList)
      } else if (isMenuId && data.menuType === 'M') {
        // 当目录节点没有被选中, 遍历树下面的菜单节点，设置为默认数据权限
        const dataMenuIds = _this.getMenuIdFilter().filter(data)
        for (var j = 0; j < dataMenuIds.length; j++) {
          _this.changeMenuOptions(dataMenuIds[j], defauleDataScopList)
        }
      } else if (isMenuId && data.menuType === 'F') {
        /* 当前节点没有选中 ，且节点是“按钮类型”,判断该节点的父节点是否是半选状态，
         * 父节点不是半选状态 且父节点是“菜单类型” 设置 父节点的数据权限为默认数据权限
         */
        // 获取该节点的父节点
        const dataParentId = data.parentId
        const halfCheckedKeys = nodefunction.halfCheckedKeys
        // 定义变量记录父节点是否是半选状态
        var isParentIdHalf = true
        for (var K = 0; K < halfCheckedKeys.length; K++) {
          if (dataParentId === halfCheckedKeys[K]) {
            // 当父节点是半选状态则 改为false
            isParentIdHalf = false
          }
        }
        if (isParentIdHalf) {
          // 父节点没有被选中,遍历树 把该节点的数据权限设为默认数据权限
          _this.changeMenuOptions(dataParentId, defauleDataScopList)
        }
      }
    },

    // 遍历树改变树的内容
    changeMenuOptions(menuId, list) {
      var _this = this
      _this.menuOptions = _this.tickMenuIdFilter(menuId, list).filter(_this.menuOptions)
      _this.selectDefaultPermissionsByRoleId()
    },

    // 监听默认数据权限是否发生变化
    selectDefaultPermissionsByRoleId() {
      getDefaultPermissionsByRoleId(this.roleId).then(resp => {
        if (resp) {
          this.defauleDataScopList = resp.data.dataScopList
        }
      })
    },

    /** 遍历整个菜单树结构 start
     *  menuId 菜单主键id
     *  objDataScopList 用于存储菜单数据权限的数组
     */
    tickMenuIdFilter: function(menuId, objDataScopList) {
      var resultArr = []
      var getTickMenuId = function(obj) {
        if (undefined === obj || obj == null || !(obj instanceof Object)) {
          return
        }
        if (obj.menuId === menuId) {
          obj.dataScopList = objDataScopList
        }
        if (obj.children != null && obj.children instanceof Array) {
          for (const child of obj.children) {
            getTickMenuId(child)
          }
        }
      }

      return {
        /**
         *  arr 树形菜单的数据
         */
        filter: function(arr) {
          resultArr = arr
          if (!(arr instanceof Array)) {
            return false
          }
          for (const rootMenu of arr) {
            getTickMenuId(rootMenu)
          }
          return resultArr
        }
      }
    },

    /**
     * 遍历菜单树中的一部分  获取菜单节点的菜单树id
     */
    getMenuIdFilter: function() {
      var resultArr = []
      var getTickMenuId = function(obj) {
        if (undefined === obj || obj == null || !(obj instanceof Object)) {
          return
        }
        if (obj.menuType === 'C') {
          resultArr.push(obj.menuId)
        }
        if (obj.children != null && obj.children instanceof Array) {
          for (const child of obj.children) {
            getTickMenuId(child)
          }
        }
      }

      return {
        filter: function(arr) {
          if (!(arr instanceof Array)) {
            return false
          }
          resultArr = []
          // for(let rootMenu of arr){
          //   getTickMenuId(rootMenu);
          // }
          getTickMenuId(arr)
          return resultArr
        }
      }
    },

    /**
     * 编辑菜单和数据权限的时候
     * 1、查找该角色分配了那些菜单
     */
    selectMenuScopeByRoleId(roleId) {
      var _this = this
      getSelectedIdAndDefaultPermissionsByRoleId(roleId).then(resp => {
        if (resp) {
          _this.roleIdAndMenuListAll = []
          // 获取被选中的菜单树id
          var menuIds = resp.data.menuIds
          _this.defauleDataScopList = resp.data.dataScopList
          _this.$nextTick(() => {
            _this.getMenuTreeData()
            _this.$refs.menu.setCheckedKeys(menuIds)
          })
        } else {
          _this.msgError(resp.message)
        }
      })
    }

  }
}
</script>
